package com.zzs.common.redis.service.impl;

import com.alibaba.fastjson2.JSON;
import com.zzs.common.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author zzs
 * @date 2025/03/17
 */
@Service
public class RedisServiceImpl implements RedisService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public Long getExpire(String key, TimeUnit unit) {
        return redisTemplate.getExpire(key, unit);
    }

    @Override
    public void expire(String key, long timeout, TimeUnit unit) {
        redisTemplate.expire(key, timeout, unit);
    }

    @Override
    public <T> void saveValue(String key, T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    @Override
    public <V> void saveValue(Map<String, V> values) {
        redisTemplate.opsForValue().multiSet(values);
    }

    @Override
    public <T> void saveValue(String key, T value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    @Override
    public <T> T getValue(String key, Class<T> clazz) {
        Object value = redisTemplate.opsForValue().get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof String) {
            return clazz.cast(value);
        }
        return JSON.parseObject(value.toString(), clazz);
    }

    @Override
    public <T> List<T> listValues(List<String> keys, Class<T> clazz) {
        List<Object> objects = redisTemplate.opsForValue().multiGet(keys);
        if (objects == null || objects.isEmpty()) {
            return null;
        }
        return JSON.parseArray(JSON.toJSONString(objects), clazz);
    }

    @Override
    public boolean removeKey(String key) {
        return redisTemplate.delete(key);
    }

    @Override
    public void increment(String key) {
        redisTemplate.opsForValue().increment(key);
    }

    @Override
    public <T> void rightPushForList(String key, T value) {
        redisTemplate.opsForList().rightPush(key, value);
    }

    @Override
    public <T> void removeFromList(String key, T value) {
        redisTemplate.opsForList().remove(key, 1, value);
    }

    @Override
    public <T> void saveForZset(String key, T value, double score) {
        redisTemplate.opsForZSet().add(key, value, score);
    }

    @Override
    public <V> void saveForZset(String key, Map<V, Double> valueScoreMap) {
        Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
        for (Map.Entry<V, Double> entry : valueScoreMap.entrySet()) {
            V value = entry.getKey();
            Double score = entry.getValue();
            tuples.add(new DefaultTypedTuple<>(value, score));
        }
        redisTemplate.opsForZSet().add(key, tuples);
    }

    @Override
    public <T> void removeFromZset(String key, T value) {
        redisTemplate.opsForZSet().remove(key, value);
    }

    @Override
    public <T> List<T> listValuesFromZset(String key, long start, long end, Class<T> clazz) {
        Set<Object> range = redisTemplate.opsForZSet().range(key, start, end);
        if (range == null || range.isEmpty()) {
            return null;
        }
        return JSON.parseArray(JSON.toJSONString(range), clazz);
    }

    @Override
    public long getSizeForZset(String key) {
        Long size = redisTemplate.opsForZSet().size(key);
        if (size == null) {
            return 0;
        }
        return size;
    }

    @Override
    public <T> Long getRankFromZSet(String key, T value) {
        return redisTemplate.opsForZSet().rank(key, value);
    }
}
